package com.bluefish.bltuan.tools;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts2.ServletActionContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;

import com.bluefish.bltuan.tools.user.UserRight;

/**
 * common action utility for action layer.
 * 
 * @author dony.xie
 * 
 */
public final class ActionUtil {

    private static final String X_FORWARDED_FOR = "x-forwarded-for";
	private static final String WL_PROXY_CLIENT_IP = "WL-Proxy-Client-IP";
    private static final String PROXY_CLIENT_IP = "Proxy-Client-IP";
    private static final String UNKNOWN = "unknown";
    private static final String IS = "is";
    private static final String GET = "get";
    private static final String DOLLAR = "$";
    private static final String SPRIT = "/";
    private static final String UTF_8 = "UTF-8";
    private static final String TEXT_CONTENT_TYPE = "text/html; charset=UTF-8";
    private static final String SEARCH_DTO = "searchDto";
    private static final String PAGE_NO = "pageNo";
    private static final Logger LOG = LoggerFactory.getLogger(ActionUtil.class);

    private ActionUtil(){
        
    }
    
    public static UserRight getCurrentUserRight(){
    	return (UserRight) getSession(ActionConstants.CURRENT_USER_RIGHT);
    }

    /**
     * get object from HttpRequest's session with the given sessionKey.
     * 
     * @param sessionKey
     * @return
     */
    public static Object getSession(String sessionKey) {
        return ServletActionContext.getRequest().getSession().getAttribute(sessionKey);
    }

    /**
     * input object into HttpRequest's session.
     * 
     * @param key
     * @param value
     */
    public static void setSession(String key, Object value) {
        ServletActionContext.getRequest().getSession().setAttribute(key, value);
    }

    /**
     * get object from HttpRequest's attribute with the given attributeKey.
     * 
     * @param sessionKey
     * @return
     */
    public static Object getAttribute(String sessionKey) {
        return ServletActionContext.getRequest().getAttribute(sessionKey);
    }

    /**
     * input object into HttpRequest's attribute.
     * 
     * @param key
     * @param value
     */
    public static void setAttribute(String key, Object value) {
        ServletActionContext.getRequest().setAttribute(key, value);
    }

    /**
     * remove object from session which mapping to the given key.
     * 
     * @param sessionKey
     */
    public static void removeSession(String sessionKey) {
        ServletActionContext.getRequest().getSession().removeAttribute(sessionKey);
    }

    /**
     * get parameter value from HttpRequest
     * 
     * @param requestKey
     * @return
     */
    public static String getRequestParameter(String requestKey) {
        return ServletActionContext.getRequest().getParameter(requestKey);
    }

    public static Object saveConditionSessionKey(Object object) {
        if (ActionUtil.getRequestParameter(PAGE_NO) == null) {
            ActionUtil.setSession(SEARCH_DTO, object);
        } else {
            return ActionUtil.getSession(SEARCH_DTO);
        }
        return object;
    }

    /**
     * write message into response with UTF-8 encoding.
     * 
     * @param message
     * @throws IOException
     */
    public static void writeResponse(String message) {

        LOG.debug("write message into response using UTF-8 encoding:\n\t " + message);

        ServletActionContext.getResponse().setContentType(TEXT_CONTENT_TYPE);
        ServletActionContext.getResponse().setHeader("Charset", UTF_8);
        ServletActionContext.getResponse().setCharacterEncoding(UTF_8);
        try {
            ServletActionContext.getResponse().getWriter().write(message);
        } catch (IOException e) {
            LOG.error("write message to response failed.");
            LOG.info(e.getMessage());
        }
    }

    /**
     * get parameter values from HttpRequest
     * 
     * @param paramKey
     * @param requestKey
     */
    public static String[] getRequestParameterValues(String paramKey) {
        return ServletActionContext.getRequest().getParameterValues(paramKey);
    }

    public static HttpServletRequest getHttpRequest() {
        return ServletActionContext.getRequest();
    }

    public static HttpServletResponse getHttpResponse() {
        return ServletActionContext.getResponse();
    }

    @SuppressWarnings("deprecation")
    public static String getContextRealPath() {
        return ServletActionContext.getRequest().getRealPath(SPRIT);
    }

    public static String getContextPath() {
        return ServletActionContext.getRequest().getContextPath();
    }

    @SuppressWarnings("unchecked")
    public static Map<String, String[]> getRequestParameterMap() {
        return ServletActionContext.getRequest().getParameterMap();
    }

    public static String arrayToString(String str[]) {
        StringBuffer temStr = new StringBuffer();
        for (int i = 0; i < str.length; i++) {
            temStr.append(str[i]);
            temStr.append(DOLLAR);
        }
        return temStr.toString();
    }

    public static String[] stringToArray(String str) {
        String[] temStr = str.split(DOLLAR);
        return temStr;
    }

    private static void writeJson(Iterator<? extends Object> s1, String[] s2, StringBuffer buf) {
        while (s1.hasNext()) {
            buf.append("{");
            Object obj = s1.next();
            for (String s : s2) {
                Method mtd = getMethod(obj.getClass(), s);
                if (mtd != null) {
                    Object value;
                    try {
                        value = mtd.invoke(obj, new Object[] {});
                        buf.append(s + ":'" + value.toString() + "',");
                    } catch (IllegalArgumentException e) {
                        LOG.info(e.getMessage());
                    } catch (IllegalAccessException e) {
                        LOG.info(e.getMessage());
                    } catch (InvocationTargetException e) {
                        LOG.info(e.getMessage());
                    }
                }
            }
            buf.append("END:'END'},");
        }
    }

    private static Method getMethod(Class<?> cls, String name) {
        try {
            Method[] mtds = cls.getMethods();
            for (Method mtd : mtds) {
                String mtdName = mtd.getName();
                if (mtdName.equalsIgnoreCase(GET + name)) {
                    return mtd;
                }
                if (mtdName.equalsIgnoreCase(IS + name)) {
                    return mtd;
                }
            }
            return null;
        } catch (SecurityException e) {
            return null;
        }
    }

    public static String toJsonString(Iterator<? extends Object> s1, String[] s2) {
        StringBuffer buffer = new StringBuffer();
        buffer.append("[");
        writeJson(s1, s2, buffer);
        buffer.append("null]");
        return buffer.toString();
    }

    public static Object getProperty(Object o, String name) {
        if (o == null)
            return null;
        Class<?>[] cs = {};
        Object[] os = {};
        String methodName = buildName(name, GET);
        Object property = invoke(o, methodName, cs, os);
        return property;
    }

    public static Object getProperty(Object o, String name, boolean bool) {
        if (o == null)
            return null;
        Class<?>[] cs = {};
        Object[] os = {};
        String methodName = null;
        if (bool)
            methodName = buildName(name, IS);
        else
            methodName = buildName(name, GET);
        Object property = invoke(o, methodName, cs, os);
        return property;
    }

    private static Object invoke(Object o, String methodName, Class<?>[] cs, Object[] os) {
        try {
            Method method = o.getClass().getMethod(methodName, cs);
            if (method != null) {
                Object value = method.invoke(o, os);
                return value;
            }
        } catch (SecurityException e) {
            LOG.info(e.getMessage());
        } catch (NoSuchMethodException e) {
            LOG.info(e.getMessage());
        } catch (IllegalArgumentException e) {
            LOG.info(e.getMessage());
        } catch (IllegalAccessException e) {
            LOG.info(e.getMessage());
        } catch (InvocationTargetException e) {
            LOG.info(e.getMessage());
        }
        return null;
    }

    private static String buildName(String name, String prefix) {
        StringBuffer buffer = new StringBuffer();
        buffer.append(prefix);
        buffer.append(name.substring(0, 1).toUpperCase(Locale.SIMPLIFIED_CHINESE));
        buffer.append(name.substring(1));
        return buffer.toString();
    }

    public static boolean equals(String s1, String s2) {
        if (s1 != null && s1.length() > 0)
            return s1.equals(s2);
        else if (s2 != null && s2.length() > 0)
            return s2.equals(s1);
        else
            return true;
    }

    public static boolean equals(Object s1, Object s2) {
        if (s1 != null)
            return s1.equals(s2);
        return s2 == null;
    }

    public static boolean online() {
        return ActionUtil.getCurrentUserId() != null;
    }

    public static void redirect(String url) {
        try {
            ServletActionContext.getResponse().sendRedirect(url);
            LOG.info("redirect to :" + url);
        } catch (IOException e) {
            LOG.info(e.getMessage());
        }
    }

    public static void removeUserId() {
        removeSession(ActionConstants.CURRENT_USER_ID);
    }

    public static String getIpAddress() {
        HttpServletRequest request = ServletActionContext.getRequest();
        String ip = request.getHeader(X_FORWARDED_FOR);
        if(isUnknowIP(ip)) {
            ip = request.getHeader(PROXY_CLIENT_IP);
        }
        if(isUnknowIP(ip)) {
            ip = request.getHeader(WL_PROXY_CLIENT_IP);
        }
        if(isUnknowIP(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }

	private static boolean isUnknowIP(String ip) {
		return ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip);
	}

	public static void storeCurrentUserRight(UserRight right) {
		setSession(ActionConstants.CURRENT_USER_RIGHT, right);
	}
	
	public static void removeCurrentUserRight() {
		removeSession(ActionConstants.CURRENT_USER_RIGHT);
	}

	public static Object getCurrentUserId() {
		return getSession(ActionConstants.CURRENT_USER_ID);
	}

	public static void storeCurrentUserID(Object id) {
		setSession(ActionConstants.CURRENT_USER_ID, id);
	}

	public static void setContentType(String contentType) {
		HttpServletResponse response = ServletActionContext.getResponse();
		response.setContentType(contentType);
	}
	

	public static void copyProperties(Object source, Object target){
		String[] ignoreProperties = new String[]{"id"};
		BeanUtils.copyProperties(source, target, ignoreProperties);
	}
}
